﻿/**
@file
@brief  CComSink的智能指针类
@version 2005-12-06 xcong created
*/

#pragma once

#include <atlcom.h>
#include "AsyncTask/Include/weak_ptr.h"


/// CComSink的智能指针类
/**
@ingroup ov_ComSink

包装CComSink的创建和Release，同时在析构时断开CHost与CComSink的关联，保证CComSinkPtr生命期结束时，CHost与CComSink已经没有关联。

<h3>维护</h3>
CComSinkPtr使用private继承CComPtr主要是禁用CComPtr的其他一些功能，例如Attach等，只保留有限的方法给外部使用。
*/


template <class Base, class CHost>
class CParamComObjectNoLock : public Base
{
public:
    typedef Base _BaseClass;
    CParamComObjectNoLock(CHost* pHost) : Base(pHost) {}
    CParamComObjectNoLock(const AsyncTask::WeakPtr<CHost>& pHost) : Base(pHost) {}
    // Set refcount to -(LONG_MAX/2) to protect destruction and 
    // also catch mismatched Release in debug builds

    // This will be made virtual again for Beta 2
    /*virtual*/ ~CParamComObjectNoLock()
    {
        m_dwRef = -(LONG_MAX / 2);
        FinalRelease();
#ifdef _ATL_DEBUG_INTERFACES
        _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown());
#endif
    }

    //If InternalAddRef or InternalRelease is undefined then your class
    //doesn't derive from CComObjectRoot
    STDMETHOD_(ULONG, AddRef)() throw() { return InternalAddRef(); }
    STDMETHOD_(ULONG, Release)() throw()
    {
        ULONG l = InternalRelease();
        if (l == 0)
            delete this;
        return l;
    }
    //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
    STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw()
	{return _InternalQueryInterface(iid, ppvObject);}
};

template<class CComSink>
class CComSinkPtr : private CComPtr<CComSink>
{
public:
    template <class CHost>
    CComSinkPtr(CHost* pHost)
    {
        CComPtr<CComSink>::p = new CParamComObjectNoLock<CComSink, CHost>(pHost);
        CComPtr<CComSink>::p->AddRef();
    }
    template <class CHost>
    CComSinkPtr(const AsyncTask::WeakPtr<CHost>& pHost)
    {
        CComPtr<CComSink>::p = new CParamComObjectNoLock<CComSink, CHost>(pHost);
        CComPtr<CComSink>::p->AddRef();
    }

    //Host析构了才会析构内部的成员CComSinkPtr对象，但此处间接保留这个指针的值便于诊断问题
    ~CComSinkPtr() //CComPtr will release p
    {
        //if (CComPtr<CComSink>::p && (DWORD)(CComPtr<CComSink>::p->m_pHost) < 0x80000000) {
        //CComPtr<CComSink>::p->m_pHost = (CComSink::CHostType*)(0x80000000 + (DWORD)(CComPtr<CComSink>::p->m_pHost));
        CComPtr<CComSink>::p->m_pHost = NULL;
        //}
    }

    ULONG GetRefCnt()
    {
        if (CComPtr<CComSink>::p)
        {
            CComPtr<CComSink>::p->AddRef();
            return CComPtr<CComSink>::p->Release();
        }

        return 0;
    }
    _NoAddRefReleaseOnCComPtr<CComSink>* operator->() const throw()
    {
        return (_NoAddRefReleaseOnCComPtr<CComSink>*)(CComPtr<CComSink>::p);
    }
    operator CComSink*() const throw()
    {
        return CComPtr<CComSink>::p;
    }
private:
    CComSinkPtr& operator=(const CComSinkPtr& rhs);
    //CComSinkPtr(const CComSinkPtr& rhs);
};
